﻿using Server.DTool;
using Server.Manager;
using Server.Protocol;
using Server.Struct;
using System;
using System.Collections.Concurrent;
using System.Net;
using System.Net.Sockets;
using System.Threading;

namespace Server.Net
{
    class RecvArgs
    {
        static Pool<RecvArgs> _pool = new(() => { return new RecvArgs(); });

        public UserToken userToken;
        public object msg;

        public static RecvArgs GetArgs()
        {
            return _pool.Take();
        }

        public static RecvArgs GetArgs(UserToken userToken, object msg)
        {
            RecvArgs args = _pool.Take();
            args.msg = msg;
            args.userToken = userToken;
            return args;
        }

        public static void RecycleArgs(RecvArgs args)
        {
            args.Clear();
            _pool.Recycle(args);
        }

        public void Clear()
        {
            userToken = default;
            msg = default;
        }

        //public RecvArgs(UserToken userToken, object msg)
        //{
        //    this.userToken = userToken;
        //    this.msg = msg;
        //}
    }

    class TCPSocket
    {
        Socket _listener;
        readonly NetSetting _setting = NetSetting.Default;

        int _curConnectNum;

        Semaphore _maxClients;

        BufferManager _bufferManager;
        SyncResPool<NetEventArgs> _argsPool;

        readonly ConcurrentQueue<RecvArgs> _recvMsg = new();
        internal ConcurrentQueue<RecvArgs> RecvMsg => _recvMsg;

        #region TCPServer()
        public TCPSocket(NetSetting setting)
        {
            _setting = setting;
        }

        public TCPSocket(IPEndPoint ip)
        {
            _setting.Address = ip;
        }

        public TCPSocket(string ip, int port)
        {
            _setting.Address = new IPEndPoint(IPAddress.Parse(ip), port);
        }

        public TCPSocket(int port)
        {
            _setting.Address = new IPEndPoint(IPAddress.Any, port);
        }
        #endregion

        public void Start()
        {
            if (_listener != null) { return; }

            _listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            _listener.Bind(_setting.Address);
            _listener.Listen(_setting.ListenCount);

            _maxClients = new Semaphore(_setting.MaxConnect, _setting.MaxConnect);
            _bufferManager = new BufferManager(_setting.MaxConnect, _setting.BufferSize * 2);
            _argsPool = new SyncResPool<NetEventArgs>(_setting.MaxConnect, CreateArgs);
            _recvMsg.Clear();
            _curConnectNum = 0;
            _argsPool.Set(BeforeTakeArgs, BeforeRecycleArgs);

            Console.WriteLine("Net Start:: {0}:{1}", _setting.Address.Address.ToString(), _setting.Address.Port);

            StartAccpt(null);
        }

        void StartAccpt(SocketAsyncEventArgs e)
        {
            if (e == null)
            {
                e = new SocketAsyncEventArgs();
                e.Completed += Completed;
            }
            else
            {
                e.AcceptSocket = null;
            }

            _maxClients.WaitOne();

            if (!_listener.AcceptAsync(e)) //如果立即有链接
            {
                ProcessAccept(e);
            }
        }

        //!!!事件绑定时，回收对象记得解绑!!!
        void ProcessAccept(SocketAsyncEventArgs e)
        {
            if (e.SocketError == SocketError.Success)
            {
                Interlocked.Increment(ref _curConnectNum);

                Socket socket = e.AcceptSocket;
                Console.WriteLine("[{1}] 进入链接\n当前连接数:{0}", _curConnectNum, socket.RemoteEndPoint.ToString());

                NetEventArgs args = _argsPool.Take();
                UserToken token = args.Token;

                token.LastTicks = DateTime.UtcNow.Ticks;
                token.Socket = socket;
                token.IsClose = false;

                args.RecvArgs.Completed -= Completed;
                args.RecvArgs.Completed += Completed;
                args.SendArgs.Completed -= Completed;
                args.SendArgs.Completed += Completed;

                StartReceive(args.RecvArgs);
                StartAccpt(e);
            }
            else
            {
                Close();
            }
        }

        void Completed(object sender, SocketAsyncEventArgs e)
        {
            switch (e.LastOperation)
            {
                case SocketAsyncOperation.Receive:
                    ProcessRecv(e);
                    break;
                case SocketAsyncOperation.Send:
                    ProcessSend(e);
                    break;
                case SocketAsyncOperation.Accept:
                    ProcessAccept(e);
                    break;
                default:
                    Console.WriteLine("IOCompleted false");
                    break;
            }
        }

        void StartReceive(SocketAsyncEventArgs e)
        {
            UserToken token = e.UserToken as UserToken;

            if (!token.Socket.ReceiveAsync(e)) //立即有数据
            {
                ProcessRecv(e);
            }
        }

        void ProcessRecv(SocketAsyncEventArgs e)
        {
            UserToken token = e.UserToken as UserToken;

            if (e.SocketError != SocketError.Success || e.BytesTransferred < 1)
            {
                token.IsClose = true;
                token.LastTicks = long.MinValue;
                return;
            }
            //TODO  处理流数据
            token.LastTicks = DateTime.UtcNow.Ticks;
            token.Parser.Push(e.Buffer, e.Offset, e.BytesTransferred);
            StartReceive(e);
        }

        void ProcessSend(SocketAsyncEventArgs e)
        {

        }

        void HeartBreath()
        {
            Console.WriteLine("HeartBreath");
            //long ticks = DateTime.UtcNow.Ticks - _heatBreathIntervalTicks;

            //_argsPool.RecycleAll((item) =>
            //{
            //    return item.Token.LastTicks < ticks;
            //});

            //TimeManager.Instance.TimeTaskScheduler.AddTask(HeartBreath, 1000);
        }

        NetEventArgs CreateArgs()
        {
            NetEventArgs e = new();
            e.RecvArgs = new();
            e.SendArgs = new();
            e.Token = new();
            e.RecvArgs.UserToken = e.Token;
            e.SendArgs.UserToken = e.Token;
            e.Token.Parser = ProtocolParser.GetUTF8Parser();
            e.Token.Parser.Complete += (msg) =>
            {
                _recvMsg.Enqueue(RecvArgs.GetArgs(e.Token, msg));
                Console.WriteLine($"TCPServer Receive from [{e.Token.IP}] {msg}");
            };
            return e;
        }

        void BeforeRecycleArgs(NetEventArgs args)
        {
            args.Token.Clear();
            _bufferManager.RecycleBuffer(args);

            Interlocked.Decrement(ref _curConnectNum);
            Console.WriteLine("[断开链接] 当前链接数：{0}", _curConnectNum);
            _maxClients.Release();
        }

        void BeforeTakeArgs(NetEventArgs args)
        {
            _bufferManager.SetBuffer(args);
        }

        public void Close()
        {
            _listener.Close();
        }
    }
}
